require 'net/http'
class Timus
  def Timus.load_problems
    1.upto 7 do |page|
      url = URI.parse('http://acm.timus.ru/problemset.aspx')
      res = Net::HTTP.start(url.host, url.port) {|http|
        http.get('/problemset.aspx?page=' + page.to_s)
      }
      body = res.body
      problem_table_selector = /(\<TABLE CLASS=\"problemset strict\"\>.*?<\/TABLE>)/
      body =~ problem_table_selector
      problem_table = $1
      problem_table.gsub!("<BR>", "") #removing it to enable rexml parsing
      doc = REXML::Document.new(problem_table)
      timus_source = Source.find_by_name("Timus")
      doc.elements[1].each_with_index do |v, i|
        if i == 0
          next
        end
          
        number = v[1][0].to_s.to_i
        name = v[2][0][0].to_s
       
        success_rate = get_changing_field(v[4][0]).to_s
        success_count = get_changing_field(v[5][0]).to_i
        p = Problem.find(:first, 
          :conditions => {:real_identifier => number, :source_id => timus_source.id})
        if p.nil?
          p = Problem.new
          p.name = name
          p.real_identifier = number
          p.source = timus_source
        end
        p.difficulty = calculate_difficulty(success_count, success_rate)
        p.save
      end
    end
  end
    
  def Timus.get_description(real_id)
    url = URI.parse('http://acm.timus.ru/problem.aspx')
    res = Net::HTTP.start(url.host, url.port) {|http|
      http.get('/problem.aspx?num=' + real_id.to_s)
    }
    problem_html_statement = res.body

    body_extractor = /(\<BODY..*)\<\/BODY\>/m
    problem_html_statement =~ body_extractor
    problem_html_statement = $1
    problem_html_statement.gsub!('<IMG SRC="/image/get.aspx', '<IMG SRC="http://acm.timus.ru/image/get.aspx')

    problem_number_remover =/(\<H2 class=\"problem_title\"\>\d{4}\.)/
    problem_html_statement.sub!(problem_number_remover, '<H2 class="problem_title">')
    problem_html_statement
      
    problem_html_statement.gsub!('<IMG SRC="/image/get.aspx', '<IMG SRC="http://acm.timus.ru/image/get.aspx')
    spare_links_remover = /(\<TR\>\<TD WIDTH=\"130\" CLASS=\"locale\"\>.*?\<\/TABLE\>\<\/TD\>\<\/TR\>\<\/TABLE\>\<\/TD\>\<\/TR\>)/
    problem_html_statement =~ spare_links_remover
    problem_html_statement.sub!($1, "")
      
    below_links_remover = /(\<DIV CLASS=\"problem_links\"\>.*)/m
    problem_html_statement.sub!(below_links_remover, "</BODY></HTML>")
    problem_number_remover =/(\<H2 class=\"problem_title\"\>\d{4}\.)/
    problem_html_statement.sub!(problem_number_remover, '<H2 class="problem_title">')
    problem_html_statement
  end
   
  @Programming_languages = {:C => 1, :CPP => 2, :Paskal => 3, :CSharp => 8, :Java => 7}
  def Timus.submit_problem(source, problem, language, user)
    judge_id = SourceUser.find(:first, :conditions => 
        {:user_id => user.id, :source_id => Source.find_by_name("Timus").id}).username
        
    #submitting the problem
    hash = {"Action" => "submit", "Source" => source, 
      "Language" => @Programming_languages[language], 
      "JudgeID" => judge_id,
      "ProblemNum" => problem.real_identifier}
    a = Net::HTTP.post_form(URI.parse('http://acm.timus.ru/submit.aspx'), hash)
    body = a.body
    
    if body.to_s =~ /Object moved/
      timus_status_url = URI.parse('http://acm.timus.ru/status.aspx')
      user_most_recent_status_page = '/status.aspx?count=10&author=' + judge_id[0, judge_id.length() - 2]
      status_extractor =/(\<TABLE class=\"status\".*?\<\/TABLE\>)/
      res = Net::HTTP.start(timus_status_url.host, timus_status_url.port) {|http|
        http.get(user_most_recent_status_page)
      }

      body = res.body
      body =~ status_extractor
      status_string = $1
      status_string.gsub!("<BR>"," ")

      status_xml = REXML::Document.new(status_string)
      status_xml.elements[1][1][0][0][0].value
    else
      nil
    end
    
  end
     
  def Timus.confirm_user(user, password)
    hash = {"Action" => "edit", "JudgeID" => user,
      "PASSWORD" => password}
    a = Net::HTTP.post_form(URI.parse('http://acm.timus.ru/authedit.aspx'), hash)
    body = a.body
    body =~ /Object moved/
  end
  
  def get
    timus_source = Source.find_by_name("Timus")
    temp_list = Run.find(:all, :conditions => {:status => nil})
    probs = temp_list.select{|run| run.problem.source == timus_source}
    res = retrieve_status(probs)
    #puts "Nqma da ima obnovqvane" if res.size == 0
    res.each_pair do |problem, status|
      problem.status = status
      problem.save
      puts "Obnovqvane"
    end
  end
  
  def retrieve_status(not_judged_runs)
    @Timus_statuses = {:OK => "Accepted", :Compile => /Compilation error/}
    runs_to_be_judged = not_judged_runs.sort_by{|temp_run| temp_run.realid}
    #puts runs_to_be_judged.inspect
    problem_statuses = {}
    timus_status_url = URI.parse('http://acm.timus.ru/status.aspx')
    next_page = '/status.aspx?count=100'
    next_page_extractor = /\<A HREF=\"(.*?)\"\>Next/
    status_extractor =/(\<TABLE class=\"status\".*?\<\/TABLE\>)/
    while !runs_to_be_judged.empty?
        
      res = Net::HTTP.start(timus_status_url.host, timus_status_url.port) {|http|
        http.get(next_page)
      }
      body = res.body
      # puts body
      body =~ next_page_extractor
      next_page =$1[-50, 50]
      next_page = next_page[next_page.index("status"), next_page.length]
      next_page.gsub!("&amp;", "&")
      next_page = "/" + next_page
 
      body =~ status_extractor
      status_string = $1
      status_string.gsub!("<BR>"," ")
 
      status_xml = REXML::Document.new(status_string)
      status_xml.elements[1].each_with_index do |val, idx|
        if idx == 0
          next
        end
        if runs_to_be_judged.empty?
          break
        end
        
        if val[0][0].to_s == runs_to_be_judged.last().realid.to_s
          if val[6][0].to_s =~ /\d/
            problem_statuses[runs_to_be_judged.last] = val[5][0].to_s
          elsif val[5][0].to_s == @Timus_statuses[:OK]
            problem_statuses[runs_to_be_judged.last] = val[5][0].to_s
          elsif val[5][0].to_s =~ @Timus_statuses[:Compile]
            problem_statuses[runs_to_be_judged.last] = @Timus_statuses[:Compile].source
          end
          runs_to_be_judged.pop
        end
      end
    end
    problem_statuses
  end
  
  private 
  def Timus.calculate_difficulty(accepts, succ_rate)
    if accepts < 100
      return 5
    elsif accepts < 200
      return 4
    elsif accepts < 400
      return 3
    elsif accepts < 650
      return 2
    else
      return 1
    end
  end
    
  def Timus.get_changing_field(field)
#    Net::HTTP.new().get
    if(field.respond_to?(:[]))
      field_value = field[0].to_s
    else
      field_value = field.to_s
    end
    field_value
  end
end
